package com.smarthospital.web.webSocket;

import com.smarthospital.common.util.SpringContextUtil;
import com.smarthospital.service.impl.IMMessageServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * websocket 客户端
 *
 */
@ServerEndpoint("/websocket/{orderId}")
@Component
@Slf4j
public class WebSocketServer {

    //socket连接池
    private static ConcurrentHashMap<String,WebSocketServer> webSocketServers = new ConcurrentHashMap<String,WebSocketServer>();

    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private CopyOnWriteArraySet<Session>  sessions = new CopyOnWriteArraySet<>();

    //接收sid
    private String orderId="";

    /**
     * 整理下思路
     * 每个订单 能发起一次聊天
     * 订单id(唯一) 作为聊天室的房间id
     * 每次连接通过session标记
     * 接入连接  onOpen 拉出房间历史信息 并附加 "以上是历史记录" 从session中判断当前用户信息  调整消息已读、未读状态
     * 接收消息    判断对方是否在线，如果不在线  将消息存入ES中(未读) 如果在线  将消息存入ES中(已读) 并发送给对方
     *关闭连接  可以不做事
     *
     * 需要一个service处理消息
     */
    /**
     * 建立连接  通过sessionId判断是不是已经纯在的聊天  单体应用 就放在服务器里
     * @param session  session 的 senderId 属性 == 用户的id
     * @param orderId  默认传订单id吧,保证唯一 应该加密
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("orderId") String orderId) {
        WebSocketServer webSocketServer = webSocketServers.get(orderId);
        /**
         * 新的聊天
         */
        if (null == webSocketServer) {
            this.sessions.add(session);
            this.orderId = orderId;
            webSocketServers.put(orderId,this);
        }else {
            webSocketServer.sessions.add(session);
            this.sessions = webSocketServer.sessions;
            this.orderId =orderId;
        }
        //是否限制聊天室人数  todo

        IMMessageServiceImpl messageService = SpringContextUtil.getBean(IMMessageServiceImpl.class);
        messageService.onOpen(sessions,session,orderId);
        log.info("有新窗口开始监听:"+orderId+",当前在线人数为" + webSocketServers.size());
    }

    /*
     * 连接关闭调用的方法
     * 医生端才可以发起关闭，发送一条系统信息给用户端  同时发起关闭订单接口
     */
    @OnClose
    public void onClose() {
        webSocketServers.remove(this.orderId);  //从map中删除
        log.info("有一连接关闭！当前在线人数为" + webSocketServers.size());
    }

    /**
     * 收到客户端消息后调用的方法
     * 存在ES中
     * 发送给对方
     *
     * @param message 客户端发送过来的消息
     **/
    @OnMessage
    public void onMessage(@PathParam("orderId") String orderId,String message, Session session) {
        log.info("收到来自窗口"+session.getId()+"的信息:"+message);
        IMMessageServiceImpl messageService = SpringContextUtil.getBean(IMMessageServiceImpl.class);
        messageService.onMessage(orderId,sessions,session,message);
    }

    /**
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误 error {}", error.getMessage(),error);
    }

}